home *** CD-ROM | disk | FTP | other *** search
/ QRZ! Ham Radio 8 / QRZ Ham Radio Callsign Database - Volume 8.iso / mac / files / t_sys5 / unixcpio.gz / unixnet.cpio / nrcmd.c < prev    next >
C/C++ Source or Header  |  1994-07-11  |  26KB  |  1,277 lines

  1. /* net/rom user command processing
  2.  * Copyright 1989 by Daniel M. Frank, W9NK.  Permission granted for
  3.  * non-commercial distribution only.
  4.  */
  5.  
  6. #include <stdio.h>
  7. #include "global.h"
  8. #include "config.h"
  9. #include "mbuf.h"
  10. #include "ax25.h"
  11. #include "timer.h"
  12. #include "iface.h"
  13. #include "lapb.h"
  14. #include "netrom.h"
  15. #include "nr4.h"
  16. #include "netuser.h"
  17. #include "tcp.h"
  18. #include "ftp.h"
  19. #include "telnet.h"
  20. #include "finger.h"
  21. #include "ax_mbx.h"
  22. #include "cmdparse.h"
  23. #include "session.h"
  24. #include <ctype.h>
  25. #ifdef    UNIX
  26. #undef    toupper
  27. #undef    tolower
  28. #include <memory.h>
  29. #include <string.h>
  30. #endif
  31.  
  32. #undef NRDEBUG
  33.  
  34. long atol();
  35. extern struct session *current;
  36.  
  37. char *Nr4states[] = {
  38.     "Disconnected",
  39.     "Conn Pending",
  40.     "Connected",
  41.     "Disc Pending"
  42. } ;
  43.  
  44. char *Nr4reasons[] = {
  45.     "Normal",
  46.     "By Peer",
  47.     "Timeout",
  48.     "Reset",
  49.     "Refused"
  50. } ;
  51.  
  52. static int dointerface(), dobcnodes(), donodetimer(), donrroute(),
  53.            donrttl(), doobsotimer(), donodefilter(), donrverbose(),
  54.            donrconnect(), donrreset(), donrwindow(), donrirtt(),
  55.            donracktime(), donrqlimit(), donrchoketime(), donrretries(),
  56.            donrstatus(), donrkick() ;
  57.  
  58. static struct cmds nrcmds[] = {
  59.     "acktime",    donracktime,    0,    NULLCHAR,    NULLCHAR,
  60.     "bcnodes",    dobcnodes,    2,    "netrom bcnodes <interface>", NULLCHAR,
  61.     
  62. /* Put connect before choketime to make it the default expansion of 'c' */
  63.  
  64.     "connect",    donrconnect,2,    "netrom connect <node>",    NULLCHAR,
  65.     "choketime",    donrchoketime,    0,    NULLCHAR,    NULLCHAR,
  66.     "interface",    dointerface,    4,
  67.         "netrom interface <interface> <alias> <quality>",    NULLCHAR,
  68.     "irtt",            donrirtt,        0,    NULLCHAR,    NULLCHAR,
  69.     "kick",            donrkick,        2,    "netrom kick <&nrcb>",    NULLCHAR,
  70.     "nodefilter",    donodefilter,    0,    NULLCHAR,    NULLCHAR,
  71.     "nodetimer",    donodetimer,    0,    NULLCHAR,    NULLCHAR,
  72.     "obsotimer",    doobsotimer,    0,    NULLCHAR,    NULLCHAR,
  73.     "qlimit",    donrqlimit,    0,    NULLCHAR,    NULLCHAR,
  74.     "reset",    donrreset,    2,    "netrom reset <&nrcb>",    NULLCHAR,
  75.     "retries",    donrretries,0,    NULLCHAR,    NULLCHAR,
  76.     "route",    donrroute,    0,    NULLCHAR,    NULLCHAR,
  77.     "status",    donrstatus,    0,    NULLCHAR,    NULLCHAR,
  78.     "ttl",        donrttl,    0,    NULLCHAR,    NULLCHAR,
  79.     "verbose",    donrverbose,0,    NULLCHAR,    NULLCHAR,
  80.     "window",    donrwindow,    0,    NULLCHAR,    NULLCHAR,
  81.     NULLCHAR,    NULLFP,        0,
  82.         "netrom subcommands: acktime bcnodes connect choketime interface irtt kick\n                    nodetimer nodefilter obsotimer qlimit reset retries route\n                    status ttl verbose window",
  83.         NULLCHAR
  84. } ;
  85.  
  86. static struct timer nodetimer ;    /* timer for nodes broadcasts */
  87. static struct timer obsotimer ;    /* timer for aging routes */
  88.  
  89. /* Command multiplexer */
  90. donetrom(argc,argv)
  91. int argc ;
  92. char *argv[] ;
  93. {
  94.     return subcmd(nrcmds,argc,argv) ;
  95. }
  96.  
  97. static int dorouteadd(), doroutedrop(), doroutedump(), dorouteinfo() ;
  98.  
  99. static struct cmds routecmds[] = {
  100.     "add",    dorouteadd,    6,
  101.         "netrom route add <alias> <destination> <interface> <quality> <neighbor>",
  102.         "add failed",
  103.     "drop",    doroutedrop, 4,
  104.         "netrom route drop <destination> <neighbor> <interface>",
  105.         "drop failed",
  106.     "info", dorouteinfo, 2,
  107.         "netrom route info <destination>", NULLCHAR,
  108.     NULLCHAR,    NULLFP,    0,
  109.         "netrom route subcommands: add drop info",
  110.         NULLCHAR
  111. } ;
  112.  
  113. /* Route command multiplexer */
  114. static
  115. donrroute(argc, argv)
  116. int argc ;
  117. char *argv[] ;
  118. {
  119.     if (argc < 2) {
  120.         doroutedump() ;
  121.         return 0 ;
  122.     }
  123.     return subcmd(routecmds,argc,argv) ;
  124. }
  125.  
  126. /* Dump a list of known routes */
  127. static
  128. doroutedump()
  129. {
  130.     register struct nrroute_tab *rp ;
  131.     register int i, column ;
  132.     char buf[32] ;
  133.     char *cp ;
  134.     int count = 0;
  135.     
  136.     column = 1 ;
  137.     
  138.     for (i = 0 ; i < NRNUMCHAINS ; i++)
  139.         for (rp = nrroute_tab[i] ; rp != NULLNRRTAB ; rp = rp->next) {
  140.             strcpy(buf,rp->alias) ;
  141.             /* remove trailing spaces */
  142.             if ((cp = index(buf,' ')) == NULLCHAR)
  143.                 cp = &buf[strlen(buf)] ;
  144.             if (cp != buf)        /* don't include colon for null alias */
  145.                 *cp++ = ':' ;
  146.             pax25(cp,&rp->call) ;
  147.             printf("%-16s  ",buf) ;
  148.             count++;
  149.             if (column++ == 4) {
  150.                 printf("\n") ;
  151.                 column = 1 ;
  152.             }
  153.         }
  154.  
  155.     if (column != 1)
  156.         printf("\n") ;
  157.     printf("Total station count = %d\n",count);
  158.         
  159.     return 0 ;
  160. }
  161.  
  162. /* print detailed information on an individual route */
  163. /*ARGSUSED*/
  164. static int
  165. dorouteinfo(argc,argv)
  166. int argc ;
  167. char *argv[] ;
  168. {
  169.     register struct nrroute_tab *rp ;
  170.     register struct nr_bind *bp ;
  171.     register struct nrnbr_tab *np ;
  172.     struct ax25_addr dest ;
  173.     char neighbor[60] ;
  174.  
  175.     if (setcall(&dest,argv[1]) == -1) {
  176.         printf ("bad destination name\n") ;
  177.         return -1 ;
  178.     }
  179.         
  180.     if ((rp = find_nrroute(&dest)) == NULLNRRTAB) {
  181.         printf("no such route\n") ;
  182.         return -1 ;
  183.     }
  184.  
  185.     for (bp = rp->routes ; bp != NULLNRBIND ; bp = bp->next) {
  186.         np = bp->via ;
  187.         psax25(neighbor,np->call) ;
  188.         printf("%1s %3d  %3d  %-8s  %s\n",
  189.                 (bp->flags & NRB_PERMANENT ? "P" :
  190.                  bp->flags & NRB_RECORDED ? "R" : " "),
  191.                 bp->quality,bp->obsocnt,
  192.                 nrifaces[np->interface].interface->name,
  193.                 neighbor) ;
  194.     }
  195.     return 0 ;
  196. }
  197.         
  198. /* convert a null-terminated alias name to a blank-filled, upcased */
  199. /* version.  Return -1 on failure. */
  200. static int
  201. putalias(to,from,complain)
  202. register char *to, *from ;
  203. int complain ;
  204. {
  205.     int len, i ;
  206.     
  207.     if ((len = strlen(from)) > ALEN) {
  208.         if (complain)
  209.             printf ("alias too long - six characters max\n") ;
  210.         return -1 ;
  211.     }
  212.     
  213.     for (i = 0 ; i < ALEN ; i++) {
  214.         if (i < len) {
  215.             if (islower(*from))
  216.                 *to++ = toupper(*from++) ;
  217.             else
  218.                 *to++ = *from++ ;
  219.         }
  220.         else
  221.             *to++ = ' ' ;
  222.     }
  223.             
  224.     *to = '\0' ;
  225.     return 0 ;
  226. }
  227.  
  228. /* Add a route */
  229. static int
  230. dorouteadd(argc, argv)
  231. int argc ;
  232. char *argv[] ;
  233. {
  234.     char alias[7] ;
  235.     struct ax25_addr dest ;
  236.     unsigned quality ;
  237.     char neighbor[AXALEN * 3] ;
  238.     register int i ;
  239.     int naddr ;
  240.  
  241.     /* format alias (putalias prints error message if necessary) */
  242.     if (putalias(alias,argv[1],1) == -1)
  243.         return -1 ;
  244.  
  245.     /* format destination callsign */
  246.     if (setcall(&dest,argv[2]) == -1) {
  247.         printf("bad destination callsign\n") ;
  248.         return -1 ;
  249.     }
  250.  
  251.     /* find interface */
  252.     for (i = 0 ; i < nr_numiface ; i++)
  253.         if (!strcmp(nrifaces[i].interface->name,argv[3]))
  254.             break ;
  255.     if (i == nr_numiface) {
  256.         printf("Interface \"%s\" not found\n",argv[3]) ;
  257.         return -1 ;
  258.     }
  259.     
  260.     /* get and check quality value */
  261.     if ((quality = atoi(argv[4])) > 255) {
  262.         printf("maximum route quality is 255\n") ;
  263.         return -1 ;
  264.     }
  265.  
  266.     /* make sure no more than 2 digis */
  267.     naddr = argc - 5 ;
  268.     if (naddr > 3) {
  269.         printf("no more than 2 digipeaters for a net/rom neighbor\n") ;
  270.         return -1 ;
  271.     }
  272.     
  273.     /* format neighbor address string */
  274.     setpath(neighbor,&argv[5],naddr) ;
  275.  
  276.     return nr_routeadd(alias,&dest,(unsigned)i,quality,neighbor,1,0) ;
  277. }
  278.  
  279.  
  280. /* drop a route */
  281. /*ARGSUSED*/
  282. static
  283. doroutedrop(argc,argv)
  284. int argc ;
  285. char *argv[] ;
  286. {
  287.     struct ax25_addr dest, neighbor ;
  288.     register int i ;
  289.  
  290.     /* format destination and neighbor callsigns */
  291.     if (setcall(&dest,argv[1]) == -1) {
  292.         printf("bad destination callsign\n") ;
  293.         return -1 ;
  294.     }
  295.     if (setcall(&neighbor,argv[2]) == -1) {
  296.         printf("bad neighbor callsign\n") ;
  297.         return -1 ;
  298.     }
  299.  
  300.     /* find interface */
  301.     for (i = 0 ; i < nr_numiface ; i++)
  302.         if (!strcmp(nrifaces[i].interface->name,argv[3]))
  303.             break ;
  304.     if (i == nr_numiface) {
  305.         printf("Interface \"%s\" not found\n",argv[3]) ;
  306.         return -1 ;
  307.     }
  308.  
  309.     return nr_routedrop(&dest,&neighbor,(unsigned)i) ;
  310. }
  311.     
  312.     
  313. /* make an interface available to net/rom */
  314. /*ARGSUSED*/
  315. static int
  316. dointerface(argc,argv)
  317. int argc ;
  318. char *argv[] ;
  319. {
  320.     int i ;
  321.     register struct interface *ifp ;
  322.     extern struct interface *ifaces ;
  323.  
  324.     if (nr_interface == NULLIF) {
  325.         printf("Attach netrom interface first\n") ;
  326.         return 1 ;
  327.     }
  328.     
  329.     if (nr_numiface >= NRNUMIFACE) {
  330.         printf("Only %d net/rom interfaces available\n",NRNUMIFACE) ;
  331.         return 1 ;
  332.     }
  333.     
  334.     for(ifp=ifaces;ifp != NULLIF;ifp = ifp->next){
  335.         if(strcmp(argv[1],ifp->name) == 0)
  336.             break;
  337.     }
  338.     if(ifp == NULLIF){
  339.         printf("Interface \"%s\" unknown\n",argv[1]);
  340.         return 1;
  341.     }
  342.     for (i = 0 ; i < nr_numiface ; i++)
  343.         if (nrifaces[i].interface == ifp) {
  344.             printf("Interface \"%s\" is already registered\n",argv[1]) ;
  345.             return 1 ;
  346.         }
  347.         
  348.     nrifaces[nr_numiface].interface = ifp ;
  349.  
  350.     if (putalias(nrifaces[nr_numiface].alias,argv[2],1) == -1)
  351.         return 1 ;
  352.         
  353.     if ((nrifaces[nr_numiface].quality = atoi(argv[3])) > 255) {
  354.         printf("Quality cannot be greater than 255\n") ;
  355.         return 1 ;
  356.     }
  357.         
  358.     nr_numiface++ ;            /* accept this interface */
  359.     return 0 ;
  360. }
  361.  
  362. /* Broadcast nodes list on named interface. */
  363.  
  364. /*ARGSUSED*/
  365. static int
  366. dobcnodes(argc,argv)
  367. int argc ;
  368. char *argv[] ;
  369. {
  370.     register int i ;
  371.     for (i = 0 ; i < nr_numiface ; i++)
  372.         if (!strcmp(nrifaces[i].interface->name,argv[1]))
  373.             break ;
  374.     if (i == nr_numiface) {
  375.         printf("Interface \"%s\" not found\n",argv[1]) ;
  376.         return 1 ;
  377.     }
  378.         
  379.     nr_bcnodes((unsigned)i) ;
  380.     return 0 ;
  381. }
  382.  
  383. #define TICKSPERSEC    (1000L / MSPTICK)    /* Ticks per second */
  384.  
  385. /* Set outbound node broadcast interval */
  386. static int
  387. donodetimer(argc,argv)
  388. int argc;
  389. char *argv[];
  390. {
  391.     int donodetick();
  392.  
  393.     if(argc < 2){
  394.         printf("%lu/%lu\n",
  395.                 (nodetimer.start - nodetimer.count)/TICKSPERSEC,
  396.                 nodetimer.start/TICKSPERSEC);
  397.         return 0;
  398.     }
  399.     stop_timer(&nodetimer) ;    /* in case it's already running */
  400.     nodetimer.func = (void (*)())donodetick;/* what to call on timeout */
  401.     nodetimer.arg = NULLCHAR;        /* dummy value */
  402.     nodetimer.start = atol(argv[1])*TICKSPERSEC;    /* set timer duration */
  403.     start_timer(&nodetimer);        /* and fire it up */
  404.     return 0;
  405. }
  406.  
  407. static int
  408. donodetick()
  409. {
  410.     register int i ;
  411.  
  412.     for (i = 0 ; i < nr_numiface ; i++)
  413.         nr_bcnodes((unsigned)i) ;
  414.  
  415.     /* Restart timer */
  416.     start_timer(&nodetimer) ;
  417. }
  418.  
  419. /* Set timer for aging routes */
  420. static int
  421. doobsotimer(argc,argv)
  422. int argc;
  423. char *argv[];
  424. {
  425.     extern int doobsotick();
  426.  
  427.     if(argc < 2){
  428.         printf("%lu/%lu\n",(obsotimer.start - obsotimer.count)/TICKSPERSEC,
  429.         obsotimer.start/TICKSPERSEC);
  430.         return 0;
  431.     }
  432.     stop_timer(&obsotimer) ;    /* just in case it's already running */
  433.     obsotimer.func = (void (*)())doobsotick;/* what to call on timeout */
  434.     obsotimer.arg = NULLCHAR;        /* dummy value */
  435.     obsotimer.start = atol(argv[1])*TICKSPERSEC;    /* set timer duration */
  436.     start_timer(&obsotimer);        /* and fire it up */
  437.     return 0;
  438. }
  439.  
  440.  
  441. /* Go through the routing table, reducing the obsolescence count of
  442.  * non-permanent routes, and purging them if the count reaches 0
  443.  */
  444. static int
  445. doobsotick()
  446. {
  447.     register struct nrnbr_tab *np ;
  448.     register struct nrroute_tab *rp, *rpnext ;
  449.     register struct nr_bind *bp, *bpnext ;
  450.     struct ax25_addr neighbor ;
  451.     int16 nrhash();
  452.     int i ;
  453.  
  454.     for (i = 0 ; i < NRNUMCHAINS ; i++) {
  455.         for (rp = nrroute_tab[i] ; rp != NULLNRRTAB ; rp = rpnext) {
  456.             rpnext = rp->next ;     /* save in case we free this route */
  457.             for (bp = rp->routes ; bp != NULLNRBIND ; bp = bpnext) {
  458.                 bpnext = bp->next ;    /* in case we free this binding */
  459.                 if (bp->flags & NRB_PERMANENT)    /* don't age these */
  460.                     continue ;
  461.                 if (--bp->obsocnt == 0) {        /* time's up! */
  462.                     if (bp->next != NULLNRBIND)
  463.                         bp->next->prev = bp->prev ;
  464.                     if (bp->prev != NULLNRBIND)
  465.                         bp->prev->next = bp->next ;
  466.                     else
  467.                         rp->routes = bp->next ;
  468.                     rp->num_routes-- ;            /* one less binding */
  469.                     np = bp->via ;                /* find the neighbor */
  470.                     free((char *)bp) ;                    /* now we can free the bind */
  471.                     /* Check to see if we can free the neighbor */
  472.                     if (--np->refcnt == 0) {
  473.                         if (np->next != NULLNTAB)
  474.                             np->next->prev = np->prev ;
  475.                         if (np->prev != NULLNTAB)
  476.                             np->prev->next = np->next ;
  477.                         else {
  478.                             memcpy(neighbor.call,np->call,ALEN) ;
  479.                             neighbor.ssid = np->call[ALEN] ;
  480.                             nrnbr_tab[(int)nrhash(&neighbor)] = np->next ;
  481.                         }
  482.                         free((char *)np) ;    /* free the storage */
  483.                     }
  484.                 }
  485.             }
  486.             if (rp->num_routes == 0) {        /* did we free them all? */
  487.                 if (rp->next != NULLNRRTAB)
  488.                     rp->next->prev = rp->prev ;
  489.                 if (rp->prev != NULLNRRTAB)
  490.                     rp->prev->next = rp->next ;
  491.                 else
  492.                     nrroute_tab[i] = rp->next ;
  493.  
  494.                 free((char *)rp) ;
  495.             }
  496.         }
  497.     }
  498.  
  499.     start_timer(&obsotimer) ;
  500. }
  501.  
  502.  
  503. static int donfadd(), donfdrop(), donfmode() ;
  504.  
  505. static struct cmds nfcmds[] = {
  506.     "add",    donfadd,    3,
  507.         "netrom nodefilter add <neighbor> <interface>",
  508.         "add failed",
  509.     "drop",    donfdrop,    3,
  510.         "netrom nodefilter drop <neighbor> <interface>",
  511.         "drop failed",
  512.     "mode",    donfmode,    0,    NULLCHAR,    NULLCHAR,
  513.     NULLCHAR,    NULLFP,    0,
  514.         "nodefilter subcommands: add drop mode",
  515.         NULLCHAR
  516. } ;
  517.  
  518. /* nodefilter command multiplexer */
  519. static
  520. donodefilter(argc,argv)
  521. int argc ;
  522. char *argv[] ;
  523. {
  524.     if (argc < 2) {
  525.         donfdump() ;
  526.         return 0 ;
  527.     }
  528.     return subcmd(nfcmds,argc,argv) ;
  529. }
  530.  
  531. /* display a list of <callsign,interface> pairs from the filter
  532.  * list.
  533.  */
  534. static
  535. donfdump()
  536. {
  537.     int i, column = 1 ;
  538.     struct nrnf_tab *fp ;
  539.     char buf[16] ;
  540.  
  541.     for (i = 0 ; i < NRNUMCHAINS ; i++)
  542.         for (fp = nrnf_tab[i] ; fp != NULLNRNFTAB ; fp = fp->next) {
  543.             pax25(buf,&fp->neighbor) ;
  544.             printf("%-7s %-8s  ",
  545.                     buf,nrifaces[fp->interface].interface->name) ;
  546.             if (column++ == 4) {
  547.                 printf("\n") ;
  548.                 column = 1 ;
  549.             }
  550.         }
  551.  
  552.     if (column != 1)
  553.         printf("\n") ;
  554.  
  555.     return 0 ;
  556. }
  557.  
  558. /* add an entry to the filter table */
  559. /*ARGSUSED*/
  560. static
  561. donfadd(argc,argv)
  562. int argc ;
  563. char *argv[] ;
  564. {
  565.     struct ax25_addr neighbor ;
  566.     register int i ;
  567.  
  568.     /* format callsign */
  569.     if (setcall(&neighbor,argv[1]) == -1) {
  570.         printf("bad neighbor callsign\n") ;
  571.         return -1 ;
  572.     }
  573.  
  574.     /* find interface */
  575.     for (i = 0 ; i < nr_numiface ; i++)
  576.         if (!strcmp(nrifaces[i].interface->name,argv[2]))
  577.             break ;
  578.     if (i == nr_numiface) {
  579.         printf("Interface \"%s\" not found\n",argv[2]) ;
  580.         return -1 ;
  581.     }
  582.  
  583.     return nr_nfadd(&neighbor,(unsigned)i) ;
  584. }
  585.  
  586. /* drop an entry from the filter table */
  587. /*ARGSUSED*/
  588. static
  589. donfdrop(argc,argv)
  590. int argc ;
  591. char *argv[] ;
  592. {
  593.     struct ax25_addr neighbor ;
  594.     register int i ;
  595.  
  596.     /* format neighbor callsign */
  597.     if (setcall(&neighbor,argv[1]) == -1) {
  598.         printf("bad neighbor callsign\n") ;
  599.         return -1 ;
  600.     }
  601.  
  602.     /* find interface */
  603.     for (i = 0 ; i < nr_numiface ; i++)
  604.         if (!strcmp(nrifaces[i].interface->name,argv[2]))
  605.             break ;
  606.     if (i == nr_numiface) {
  607.         printf("Interface \"%s\" not found\n",argv[2]) ;
  608.         return -1 ;
  609.     }
  610.  
  611.     return nr_nfdrop(&neighbor,(unsigned)i) ;
  612. }
  613.  
  614. /* nodefilter mode subcommand */
  615. static
  616. donfmode(argc,argv)
  617. int argc ;
  618. char *argv[] ;
  619. {
  620.     if (argc < 2) {
  621.         printf("filter mode is ") ;
  622.         switch (nr_nfmode) {
  623.             case NRNF_NOFILTER:
  624.                 printf("none\n") ;
  625.                 break ;
  626.             case NRNF_ACCEPT:
  627.                 printf("accept\n") ;
  628.                 break ;
  629.             case NRNF_REJECT:
  630.                 printf("reject\n") ;
  631.                 break ;
  632.             default:
  633.                 printf("some strange, unknown value\n") ;
  634.         }
  635.         return 0 ;
  636.     }
  637.     
  638.     switch (argv[1][0]) {
  639.         case 'n':
  640.         case 'N':
  641.             nr_nfmode = NRNF_NOFILTER ;
  642.             break ;
  643.         case 'a':
  644.         case 'A':
  645.             nr_nfmode = NRNF_ACCEPT ;
  646.             break ;
  647.         case 'r':
  648.         case 'R':
  649.             nr_nfmode = NRNF_REJECT ;
  650.             break ;
  651.         default:
  652.             printf("modes are: none accept reject\n") ;
  653.             return -1 ;
  654.     }
  655.  
  656.     return 0 ;
  657. }
  658.  
  659.  
  660. /* netrom network packet time-to-live initializer */
  661. static
  662. donrttl(argc, argv)
  663. int argc ;
  664. char *argv[] ;
  665. {
  666.     int val ;
  667.  
  668.     if (argc < 2) {
  669.         printf("%d\n", nr_ttl) ;
  670.         return 0 ;
  671.     }
  672.  
  673.     val = atoi(argv[1]) ;
  674.  
  675.     if (val < 0 || val > 255) {
  676.         printf("ttl must be between 0 and 255\n") ;
  677.         return 1 ;
  678.     }
  679.  
  680.     nr_ttl = val ;
  681.  
  682.     return 0 ;
  683. }
  684.  
  685. /* verbose route broadcast */
  686. static
  687. donrverbose(argc,argv)
  688. int argc ;
  689. char *argv[] ;
  690. {
  691.     if (argc < 2) {
  692.         printf("verbose is %s\n", nr_verbose ? "yes" : "no" ) ;
  693.         return 0 ;
  694.     }
  695.     
  696.     switch (argv[1][0]) {
  697.         case 'n':
  698.         case 'N':
  699.             nr_verbose = 0 ;
  700.             break ;
  701.         case 'y':
  702.         case 'Y':
  703.             nr_verbose = 1 ;
  704.             break ;
  705.         default:
  706.             printf("use: netrom verbose [yes|no]\n") ;
  707.             return -1 ;
  708.     }
  709.  
  710.     return 0 ;
  711. }
  712.  
  713. /* Initiate a NET/ROM transport connection */
  714. /*ARGSUSED*/
  715. static int
  716. donrconnect(argc,argv)
  717. int argc ;
  718. char *argv[] ;
  719. {
  720.     struct ax25_addr node, *np ;
  721.     struct session *s ;
  722.     char alias[7] ;
  723.  
  724.     /* See if the requested destination could be an alias, and */
  725.     /* find and use it if it is.  Otherwise assume it is an ax.25 */
  726.     /* address. */
  727.     
  728.     if (putalias(alias,argv[1],0) != -1 &&
  729.         (np = find_nralias(alias)) != NULLAXADDR)
  730.           node = *np ;
  731.     else
  732.         setcall(&node,argv[1]) ;    /* parse ax25 callsign */
  733.  
  734.     /* Get a session descriptor */
  735.  
  736.     if ((s = newsession()) == NULLSESSION) {
  737.         printf("Too many sessions\n") ;
  738.         return 1 ;
  739.     }
  740.  
  741.     if((s->name = malloc((unsigned)strlen(argv[1])+1)) != NULLCHAR)
  742.         strcpy(s->name,argv[1]);
  743.     s->type = NRSESSION ;
  744.     s->parse = (int (*)())nr4_parse ;
  745.     current = s;
  746.  
  747.     s->cb.nr4_cb = open_nr4(&node,&mycall,nr4_rx,nr4_tx,nr4_state,(char *)s) ;
  748.     go() ;
  749.     return 0 ;
  750. }
  751.  
  752. /* Display changes in NET/ROM state */
  753. /*ARGSUSED*/
  754. void
  755. nr4_state(cb,old,new)
  756. struct nr4cb *cb ;
  757. int old,new;
  758. {
  759.     struct session *s;
  760.  
  761.     s = (struct session *)cb->puser;
  762.  
  763.     if(current != NULLSESSION && current->type == NRSESSION && current == s){
  764.         printf("%s",Nr4states[new]);
  765.         if(new == NR4STDISC) {
  766.             printf(" (%s)\n", Nr4reasons[cb->dreason]) ;
  767.             cmdmode();
  768.         } else
  769.             printf("\n") ;
  770.         fflush(stdout);
  771.     }
  772.     if(new == NR4STDISC){
  773.         cb->puser = NULLCHAR;
  774.         freesession(s);
  775.     }
  776. }
  777.  
  778. /* Handle typed characters on a NET/ROM connection */
  779. void
  780. nr4_parse(buf,cnt)
  781. char *buf;
  782. int16 cnt;
  783. {
  784.     struct mbuf *bp;
  785.     register char *cp;
  786.     int16 size, i ;
  787.     char c;
  788.  
  789.     if(current == NULLSESSION || current->type != NRSESSION)
  790.         return;    /* "can't happen" */
  791.  
  792.     /* If recording is on, record outgoing stuff too */
  793.     if(current->record != NULLFILE)
  794.         fwrite(buf,1,(int)cnt,current->record);
  795.  
  796.     /* Parse it out, splitting at transport frame boundaries */
  797.     
  798.     while (cnt != 0) {
  799. #ifdef NRDEBUG
  800.         printf("Once around the parse loop - cnt = %d\n", cnt) ;
  801. #endif
  802.         size = min(cnt, NR4MAXINFO) ;
  803.         if ((bp = alloc_mbuf(size)) == NULLBUF)
  804.             break ;
  805.         /* Copy keyboard buffer to output, stripping line feeds */
  806.         cp = bp->data ;
  807.         for (i = 0 ; i < size ; i++){
  808.             c = *buf++;
  809.             if(c != '\n'){
  810.                 *cp++ = c;
  811.                 bp->cnt++;
  812.             }
  813.         }
  814.         cnt -= size ;
  815.         send_nr4(current->cb.nr4_cb,bp);
  816.     }
  817. }
  818.  
  819. /* Handle new incoming terminal sessions
  820.  * This is the default state change upcall function, used when
  821.  * someone else connects to us
  822.  */
  823. /*ARGSUSED*/
  824. void
  825. nr4_incom(cb,oldstate,newstate)
  826. struct nr4cb *cb ;
  827. int oldstate ;
  828. int newstate ;
  829. {
  830.     void nr4_session(), mbx_nr4incom() ;
  831.  
  832.     if (newstate != NR4STCON)        /* why are you bothering us? */
  833.         return ;                    /* (shouldn't happen) */
  834.         
  835.     if (ax25mbox)
  836.         mbx_nr4incom(cb) ;
  837.     else
  838.         nr4_session(cb) ;
  839.     return ;
  840.  
  841. }
  842.  
  843. /* This function sets up a NET/ROM chat session */
  844. void
  845. nr4_session(cb)
  846. struct nr4cb *cb ;
  847. {
  848.     struct session *s;
  849.     char remote[10];
  850.  
  851.     pax25(remote,&cb->user);
  852.     if((s = newsession()) == NULLSESSION){
  853.         /* Out of sessions */
  854.         disc_nr4(cb);
  855.         return;
  856.     }
  857.     s->type = NRSESSION ;
  858.     s->name = malloc((int16)strlen(remote)+1);
  859.     s->cb.nr4_cb = cb ;
  860.     s->parse = (int (*)())nr4_parse;
  861.     strcpy(s->name,remote);
  862.     cb->r_upcall = nr4_rx;
  863.     cb->s_upcall = nr4_state;
  864.     cb->t_upcall = nr4_tx;
  865.     cb->puser = (char *)s;
  866. #if    (defined(MAC) || defined(AMIGA))
  867.     printf("\007Incoming NET/ROM session %lu from %s\n",s - sessions,remote);
  868. #else
  869.     printf("\007Incoming NET/ROM session %u from %s\n",s - sessions,remote);
  870. #endif
  871.     fflush(stdout);
  872. }
  873.  
  874. /* Handle incoming terminal traffic */
  875. void
  876. nr4_rx(cb,cnt)
  877. struct nr4cb *cb ;
  878. int16 cnt;
  879. {
  880.     register struct mbuf *bp;
  881.     char c;
  882.  
  883.     /* Hold output if we're not the current session */
  884.     if(mode != CONV_MODE || current == NULLSESSION
  885.      || current->type != NRSESSION || current->cb.nr4_cb != cb)
  886.         return;
  887.  
  888.     if((bp = recv_nr4(cb,cnt)) == NULLBUF)
  889.         return;
  890.  
  891.     /* Display received characters, translating CR's to CR/LF */
  892.     while(bp != NULLBUF){
  893.         while(bp->cnt-- != 0){
  894.             c = *bp->data++;
  895.             if(c == '\r')
  896.                 c = '\n';
  897.             putchar(c);
  898.             if(current->record){
  899. #ifndef UNIX
  900.                 if(c == '\n')
  901.                     fputc('\r',current->record);
  902. #endif
  903.                 fputc(c,current->record);
  904.             }
  905.         }
  906.         bp = free_mbuf(bp);
  907.     }
  908.     if(current->record)
  909.         fflush(current->record);
  910.     fflush(stdout);
  911. }
  912.  
  913. /* Handle transmit upcalls. Used only for file uploading */
  914. void
  915. nr4_tx(cb,cnt)
  916. struct nr4cb *cb ;
  917. int16 cnt;
  918. {
  919.     register char *cp;
  920.     struct session *s;
  921.     register struct mbuf *bp;
  922.     int16 size;
  923.     int c;
  924.  
  925.     if((s = (struct session *)cb->puser) == NULLSESSION
  926.      || s->upload == NULLFILE)
  927.         return;
  928.     while(cnt != 0){
  929.         size = min(cnt,NR4MAXINFO);
  930.         if((bp = alloc_mbuf(size)) == NULLBUF)
  931.             break;
  932.         cp = bp->data;
  933.  
  934.         /* Now send data characters, translating between local
  935.          * keyboard end-of-line sequences and the (unwritten)
  936.          * AX.25 convention, which is carriage-return only
  937.          */
  938.          
  939.         while(bp->cnt < size){
  940.             if((c = getc(s->upload)) == EOF)
  941.                 break;
  942. #ifdef    MSDOS
  943.             /* MS-DOS gives cr-lf */
  944.             if(c == '\n')
  945.                 continue;
  946. #endif
  947. #if    (defined(UNIX) || defined(MAC) || defined(AMIGA))
  948.             /* These give lf only */
  949.             if(c == '\n')
  950.                 c = '\r';
  951. #endif
  952.             *cp++ = c;
  953.             bp->cnt++;
  954.         }    
  955.         cnt -= bp->cnt;
  956.         
  957.         if (bp->cnt != 0)    /* might happen with a newline at EOF */
  958.             send_nr4(cb,bp);
  959.         else
  960.             free_p(bp) ;
  961.             
  962.         if (c == EOF)
  963.             break ;
  964.     }
  965.     if(cnt != 0){
  966.         /* Error or end-of-file */
  967.         fclose(s->upload);
  968.         s->upload = NULLFILE;
  969.         free(s->ufile);
  970.         s->ufile = NULLCHAR;
  971.     }
  972. }
  973.  
  974. /* Reset a net/rom connection abruptly */
  975.  
  976. /*ARGSUSED*/
  977. static int
  978. donrreset(argc,argv)
  979. int argc;
  980. char *argv[];
  981. {
  982.     struct nr4cb *cb ;
  983.     extern char notval[];
  984.  
  985.     cb = (struct nr4cb *)htol(argv[1]);
  986.     if(!nr4valcb(cb)){
  987.         printf(notval);
  988.         return 1;
  989.     }
  990.     reset_nr4(cb);
  991.     return 0;
  992. }
  993.  
  994. /* Force retransmission on a net/rom connection */
  995.  
  996. /*ARGSUSED*/
  997. static int
  998. donrkick(argc,argv)
  999. int argc;
  1000. char *argv[];
  1001. {
  1002.     struct nr4cb *cb ;
  1003.     extern char notval[];
  1004.  
  1005.     cb = (struct nr4cb *)htol(argv[1]);
  1006.  
  1007.     if (kick_nr4(cb) == -1) {
  1008.         printf(notval);
  1009.         return 1;
  1010.     } else
  1011.         return 0;
  1012. }
  1013.  
  1014. /* netrom transport ACK delay timer */
  1015.  
  1016. static
  1017. donracktime(argc, argv)
  1018. int argc ;
  1019. char *argv[] ;
  1020. {
  1021.     long val ;
  1022.  
  1023.     if (argc < 2) {
  1024.         printf("%lu\n", Nr4acktime) ;
  1025.         return 0 ;
  1026.     }
  1027.  
  1028.     val = atol(argv[1]) ;
  1029.  
  1030.     Nr4acktime = val ;
  1031.  
  1032.     return 0 ;
  1033. }
  1034.  
  1035. /* netrom transport choke timeout */
  1036.  
  1037. static
  1038. donrchoketime(argc, argv)
  1039. int argc ;
  1040. char *argv[] ;
  1041. {
  1042.     long val ;
  1043.  
  1044.     if (argc < 2) {
  1045.         printf("%lu\n", Nr4choketime) ;
  1046.         return 0 ;
  1047.     }
  1048.  
  1049.     val = atol(argv[1]) ;
  1050.  
  1051.     Nr4choketime = val ;
  1052.  
  1053.     return 0 ;
  1054. }
  1055.  
  1056. /* netrom transport initial round trip time */
  1057.  
  1058. static
  1059. donrirtt(argc, argv)
  1060. int argc ;
  1061. char *argv[] ;
  1062. {
  1063.     long val ;
  1064.  
  1065.     if (argc < 2) {
  1066.         printf("%lu\n", Nr4irtt) ;
  1067.         return 0 ;
  1068.     }
  1069.  
  1070.     val = atol(argv[1]) ;
  1071.  
  1072.     Nr4irtt = val ;
  1073.  
  1074.     return 0 ;
  1075. }
  1076.  
  1077. /* netrom transport receive queue length limit.  This is the */
  1078. /* threshhold at which we will CHOKE the sender. */
  1079.  
  1080. static
  1081. donrqlimit(argc, argv)
  1082. int argc ;
  1083. char *argv[] ;
  1084. {
  1085.     unsigned val ;
  1086.  
  1087.     if (argc < 2) {
  1088.         printf("%u\n", Nr4qlimit) ;
  1089.         return 0 ;
  1090.     }
  1091.  
  1092.     val = atoi(argv[1]) ;
  1093.  
  1094.     if (val == 0) {
  1095.         printf("You cannot set the queue limit to 0\n") ;
  1096.         return 1 ;
  1097.     }
  1098.     
  1099.     Nr4qlimit = val ;
  1100.  
  1101.     return 0 ;
  1102. }
  1103.  
  1104. /* netrom transport maximum window.  This is the largest send and */
  1105. /* receive window we may negotiate */
  1106.  
  1107. static
  1108. donrwindow(argc, argv)
  1109. int argc ;
  1110. char *argv[] ;
  1111. {
  1112.     unsigned val ;
  1113.  
  1114.     if (argc < 2) {
  1115.         printf("%u\n", Nr4window) ;
  1116.         return 0 ;
  1117.     }
  1118.  
  1119.     val = atoi(argv[1]) ;
  1120.  
  1121.     if (val == 0 || val > NR4MAXWIN) {
  1122.         printf("Illegal NET/ROM window size.  Range is [1,%d]\n",
  1123.                NR4MAXWIN) ;
  1124.         return 1 ;
  1125.     }
  1126.     
  1127.     Nr4window = val ;
  1128.  
  1129.     return 0 ;
  1130. }
  1131.  
  1132. /* netrom transport maximum retries.  This is used in connect and */
  1133. /* disconnect attempts; I haven't decided what to do about actual */
  1134. /* data retries yet. */
  1135.  
  1136. static
  1137. donrretries(argc, argv)
  1138. int argc ;
  1139. char *argv[] ;
  1140. {
  1141.     unsigned val ;
  1142.  
  1143.     if (argc < 2) {
  1144.         printf("%u\n", Nr4retries) ;
  1145.         return 0 ;
  1146.     }
  1147.  
  1148.     val = atoi(argv[1]) ;
  1149.  
  1150.     if (val == 0) {
  1151.         printf("Impatient, aren't we?  Zero retries not possible\n") ;
  1152.         return 1 ;
  1153.     }
  1154.     
  1155.     Nr4retries = val ;
  1156.  
  1157.     return 0 ;
  1158. }
  1159.  
  1160. /* Display the status of NET/ROM connections */
  1161.  
  1162. static
  1163. donrstatus(argc, argv)
  1164. int argc ;
  1165. char *argv[] ;
  1166. {
  1167.     int i ;
  1168.     struct nr4cb *cb ;
  1169.     char luser[10], ruser[10], node[10] ;
  1170.     extern char notval[] ;
  1171.     void donrdump() ;
  1172.     
  1173.     if (argc < 2) {
  1174.         printf("     &CB Snd-W Snd-Q Rcv-Q     LUser      RUser @Node     State\n");
  1175.         for (i = 0 ; i < NR4MAXCIRC ; i++) {
  1176.             if ((cb = Nr4circuits[i].ccb) == NULLNR4CB)
  1177.                 continue ;
  1178.             pax25(luser,&cb->luser) ;
  1179.             pax25(ruser,&cb->user) ;
  1180.             pax25(node,&cb->node) ;
  1181.             printf("%8lx   %3d %5d %5d %9s  %9s %-9s %s\n",
  1182.                    (long)cb, cb->nbuffered, len_q(cb->txq),
  1183.                    len_mbuf(cb->rxq), luser, ruser, node,
  1184.                    Nr4states[cb->state]) ;
  1185.         }
  1186.         return 0 ;
  1187.     }
  1188.  
  1189.     cb = (struct nr4cb *)htol(argv[1]) ;
  1190.     if (!nr4valcb(cb)) {
  1191.         printf(notval) ;
  1192.         return 1 ;
  1193.     }
  1194.  
  1195.     donrdump(cb) ;
  1196.     return 0 ;
  1197. }
  1198.  
  1199. /* Dump one control block */
  1200.  
  1201. static void
  1202. donrdump(cb)
  1203. struct nr4cb *cb ;
  1204. {
  1205.     char luser[10], ruser[10], node[10] ;
  1206.     unsigned seq ;
  1207.     struct nr4txbuf *b ;
  1208.     struct timer *t ;
  1209.  
  1210.     pax25(luser,&cb->luser) ;
  1211.     pax25(ruser,&cb->user) ;
  1212.     pax25(node, &cb->node) ;
  1213.  
  1214.     printf("Local: %s %d/%d Remote: %s @ %s %d/%d State: %s\n",
  1215.            luser, cb->mynum, cb->myid, ruser, node,
  1216.            cb->yournum, cb->yourid, Nr4states[cb->state]) ;
  1217.  
  1218.     printf("Window: %-5u Rxpect: %-5u RxNext: %-5u RxQ: %-5d %s\n",
  1219.            cb->window, uchar(cb->rxpected), uchar(cb->rxpastwin),
  1220.            len_mbuf(cb->rxq), cb->qfull ? "RxCHOKED" : "") ;
  1221.  
  1222.     printf(" Unack: %-5u Txpect: %-5u TxNext: %-5u TxQ: %-5d %s\n",
  1223.            cb->nbuffered, uchar(cb->ackxpected), uchar(cb->nextosend),
  1224.            len_q(cb->txq), cb->choked ? "TxCHOKED" : "") ;
  1225.  
  1226.     printf("TACK: ") ;
  1227.     if (run_timer(&cb->tack))
  1228.         printf("%lu", (cb->tack.start - cb->tack.count) * MSPTICK) ;
  1229.     else
  1230.         printf("stop") ;
  1231.     printf("/%lu ms; ", cb->tack.start * MSPTICK) ;
  1232.  
  1233.     printf("TChoke: ") ;
  1234.     if (run_timer(&cb->tchoke))
  1235.         printf("%lu", (cb->tchoke.start - cb->tchoke.count) * MSPTICK) ;
  1236.     else
  1237.         printf("stop") ;
  1238.     printf("/%lu ms; ", cb->tchoke.start * MSPTICK) ;
  1239.  
  1240.     printf("TCD: ") ;
  1241.     if (run_timer(&cb->tcd))
  1242.         printf("%lu", (cb->tcd.start - cb->tcd.count) * MSPTICK) ;
  1243.     else
  1244.         printf("stop") ;
  1245.     printf("/%lu ms", cb->tcd.start * MSPTICK) ;
  1246.  
  1247.     if (run_timer(&cb->tcd))
  1248.         printf("; Tries: %u\n", cb->cdtries) ;
  1249.     else
  1250.         printf("\n") ;
  1251.  
  1252.     printf("Backoff Level %u SRTT %ld ms Mean dev %ld ms\n",
  1253.            cb->blevel, cb->srtt, cb->mdev) ;
  1254.  
  1255.     /* If we are connected and the send window is open, display */
  1256.     /* the status of all the buffers and their timers */
  1257.     
  1258.     if (cb->state == NR4STCON && cb->nextosend != cb->ackxpected) {
  1259.  
  1260.         printf("TxBuffers:  Seq  Size  Tries  Timer\n") ;
  1261.  
  1262.         for (seq = cb->ackxpected ;
  1263.              nr4between(cb->ackxpected, seq, cb->nextosend) ;
  1264.              seq = (seq + 1) & NR4SEQMASK) {
  1265.  
  1266.             b = &cb->txbufs[seq % cb->window] ;
  1267.             t = &b->tretry ;
  1268.  
  1269.             printf("            %3u   %3d  %5d  %lu/%lu\n",
  1270.                    seq, len_mbuf(b->data), b->retries + 1,
  1271.                    (t->start - t->count) * MSPTICK, t->start * MSPTICK) ;
  1272.         }
  1273.  
  1274.     }
  1275.  
  1276. }
  1277.